﻿// -----------------------------------------------------------------------
// <copyright file="SearchController.cs" company="Abyssalsoft">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace Metal.Player.Playlist
{
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Reflection;
    using System.Text;
    using System.Windows.Forms;

    /// <summary>
    /// Search controller
    /// </summary>
    public class SearchController
    {
        #region Members

        /// <summary>Stores our view to communicate with the mask</summary>
        private static ISearchView view;

        /// <summary>The data set used to bind the list</summary>
        private static DataSet dataSet;

        /// <summary>The binding source (current playlist)</summary>
        private BindingSource source;

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the SearchController class.
        /// </summary>
        /// <param name="iView">Interface to communicate with the mask</param>
        public SearchController(ISearchView iView)
        {
            view = iView;
            this.SubscribeToViewEvents();

            this.source = new BindingSource();
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the playlist data set
        /// </summary>
        public static DataSet ListDataSet
        {
            get
            {
                return dataSet;
            }

            set
            {
                dataSet = value;
            }
        }

        /// <summary>
        /// Gets or sets the interface to communicate with the mask
        /// </summary>
        internal static ISearchView View
        {
            get
            {
                return view;
            }

            set
            {
                view = value;
            }
        }

        #endregion

        #region Private methods

        /// <summary>
        /// Subscribe to events defined in the view
        /// </summary>
        private void SubscribeToViewEvents()
        {
            view.MaskLoad += new EventHandler(this.OnMaskLoad);
            view.MaskClose += new EventHandler(this.OnMaskClose);
            view.ControlAdded += new System.Windows.Forms.ControlEventHandler(this.OnControlAdded);
        }

        /// <summary>
        /// Play selected file
        /// </summary>
        private void ListDoubleClick()
        {
            try
            {
                Core.Player.Playback.Instance.Open(SearchController.View.ListSelectedRow.Cells[1].Value.ToString());
                Core.Player.Playback.Instance.Play();

                // Select item in our playlist
                PlaylistController.SelectListRow(1, SearchController.View.ListSelectedRow.Cells[1].Value.ToString());
                PlaylistController.CurrentView.ScrollListToIndex = Convert.ToInt32(PlaylistController.CurrentView.ListSelectedRow.Index);

                // Remove filter
                this.source.RemoveFilter();

                View.IForm.Close();
            }
            catch (Exception ex)
            {
                Metal.User.UserMessage.ShowError(ex);
            }
        }

        #endregion

        #region Mask events

        /// <summary>
        /// This method is called when the mask is loaded.
        /// </summary>
        /// <param name="sender">Object sender</param>
        /// <param name="e">Event arguments</param>
        private void OnMaskLoad(object sender, EventArgs e)
        {
            try
            {
                // Create a new instance
                ListDataSet = new DataSet();

                // Load the dataset - here we must make a copy of the dataset. We don't want to filter the playlist, we filter only the list in the search window.
                ListDataSet = PlaylistController.ListDataSet.Copy();

                // Update
                View.ListDataSet = ListDataSet;
            }
            catch (Exception ex)
            {
                Metal.User.UserMessage.ShowError(ex);
            }
        }

        /// <summary>
        /// This method is called when the mask is closed.
        /// </summary>
        /// <param name="sender">Object sender</param>
        /// <param name="e">Event arguments</param>
        private void OnMaskClose(object sender, EventArgs e)
        {
            try
            {
                // Remove filter
                this.source.RemoveFilter();
                view = null;
            }
            catch (Exception ex)
            {
                Metal.User.UserMessage.ShowError(ex);
            }
        }

        /// <summary>
        /// This method is called when a control is added on the mask
        /// </summary>
        /// <param name="sender">Object sender</param>
        /// <param name="e">Event arguments</param>
        private void OnControlAdded(object sender, System.Windows.Forms.ControlEventArgs e)
        {
            try
            {
                if (e.Control.GetType() == typeof(Gui.Controls.MetalList))
                {
                    e.Control.DoubleClick += new EventHandler(this.OnListDoubleClick);
                    if ((e.Control as Gui.Controls.MetalList).ContextMenuStrip != null)
                    {
                        (e.Control as Gui.Controls.MetalList).ContextMenuStrip.ItemClicked += new ToolStripItemClickedEventHandler(this.OnContextMenuClick);
                    }
                }
                else if (e.Control.GetType() == typeof(Gui.Controls.MetalTextBox))
                {
                    e.Control.TextChanged += new EventHandler(this.OnSearchTextChanged);
                    e.Control.KeyUp += new KeyEventHandler(this.OnSearchKeyPress);
                }
                else if (e.Control.GetType() == typeof(Gui.Controls.MetalPanel))
                {
                    e.Control.ControlAdded += new System.Windows.Forms.ControlEventHandler(this.OnControlAdded);
                }
            }
            catch (Exception ex)
            {
                Metal.User.UserMessage.ShowError(ex);
            }
        }

        #endregion

        #region Controls events

        /// <summary>
        /// This event occurs on DoubleClick event
        /// </summary>
        /// <param name="sender">Object sender</param>
        /// <param name="e">Event args</param>
        private void OnListDoubleClick(object sender, EventArgs e)
        {
            try
            {
                Type thisType = typeof(SearchController);
                MethodInfo theMethod = thisType.GetMethod(((Gui.Controls.MetalList)sender).Name + "DoubleClick", BindingFlags.NonPublic | BindingFlags.Instance);
                if (theMethod != null)
                {
                    theMethod.Invoke(this, null);
                }
            }
            catch (Exception ex)
            {
                Metal.User.UserMessage.ShowError(ex);
            }
        }

        string currentTypedText;

        /// <summary>
        /// This event occurs on text changed
        /// </summary>
        /// <param name="sender">Object sender</param>
        /// <param name="e">Event args</param>
        private void OnSearchTextChanged(object sender, EventArgs e)
        {
            try
            {
                // Remove enter
                this.currentTypedText = (sender as TextBox).Text.Replace("\r\n", string.Empty);

                // The ' character breaks the filter syntax. Replacing the single quotes (apostrophes) with two single quotes will do the job :)
                this.currentTypedText = this.currentTypedText.Replace("'", "''");

                // Filter the results
                this.source.DataSource = ListDataSet.Tables[0];
                this.source.Filter = string.Format("FileName LIKE '*{0}*'", currentTypedText);
            }
            catch (Exception ex)
            {
                Metal.User.UserMessage.ShowError(ex);
            }
        }

                /// <summary>
        /// This event occurs on text changed
        /// </summary>
        /// <param name="sender">Object sender</param>
        /// <param name="e">Event args</param>
        private void OnSearchKeyPress(object sender, KeyEventArgs e)
        {
            try
            {
                if (e.KeyCode == Keys.Return)
                {
                    // Play selected file
                    string selectedFile = SearchController.View.ListSelectedRow.Cells[1].Value.ToString();

                    Core.Player.Playback.Instance.Open(selectedFile);
                    Core.Player.Playback.Instance.Play();

                    // Select item in our playlist
                    PlaylistController.SelectListRow(1, selectedFile);
                    PlaylistController.CurrentView.ScrollListToIndex = Convert.ToInt32(PlaylistController.CurrentView.ListSelectedRow.Index);

                    // Remove filter
                    this.source.RemoveFilter();

                    View.IForm.Close();
                }
                else if (e.KeyCode == Keys.Escape)
                {
                    view.IForm.Close();
                }
            }
            catch (Exception ex)
            {
                Metal.User.UserMessage.ShowError(ex);
            }
        }

        /// <summary>
        /// This event occurs when the user clicks on menu
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="e">ToolStripItem event args</param>
        private void OnContextMenuClick(object sender, ToolStripItemClickedEventArgs e)
        {
            try
            {
                string methodName = e.ClickedItem.Tag.ToString();

                // Call the method via reflection
                Type thisType = typeof(SearchLogic);
                System.Reflection.MethodInfo theMethod = thisType.GetMethod(methodName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
                if (theMethod != null)
                {
                    theMethod.Invoke(SearchLogic.Instance, null);
                }
            }
            catch (Exception ex)
            {
                Metal.User.UserMessage.ShowError(ex);
            }
        }

        #endregion
    }
}
